<?php

namespace app\common\util;

use Closure;

final class ArrayUtil
{
    /**
     * 全部满足条件
     *
     * @param array|\Traversable $array
     * @param \Closure $func 一个函数表示 ($item): bool
     *
     * @return bool
     */
    public static function all(array|\Traversable $array, Closure $func): bool
    {
        foreach ($array as $item) {
            if (!$func($item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 任意满足条件
     *
     * @param array|\Traversable $array
     * @param \Closure $func 一个函数表示 ($item): bool
     *
     * @return bool
     */
    public static function any(array|\Traversable $array, Closure $func): bool
    {
        foreach ($array as $item) {
            if ($func($item)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 返回满足条件的一个元素
     *
     * @template T
     * @param array<T>|\Traversable<T> $array
     * @param \Closure $func 一个函数表示 ($item): bool
     *
     * @return T|false
     */
    public static function find(array|\Traversable $array, Closure $func)
    {
        foreach ($array as $item) {
            if ($func($item)) {
                return $item;
            }
        }
        return false;
    }

    /**
     * 返回重复的数组
     *
     * @param mixed $data
     * @param int $num
     *
     * @return array
     */
    public static function repeat(mixed $data, int $num): array
    {
        return array_merge(...array_fill(0, $num, $data));
    }

    /**
     * 返回重复的数组（通过闭包）
     *
     * @param Closure $fn
     * @param int $num
     *
     * @return array
     */
    public static function repeatFn(Closure $fn, int $num): array
    {
        $arr = [];
        for ($i = 0; $i < $num; $i++) {
            $arr[] = $fn();
        }
        return $arr;
    }

    /**
     * 通过一个生成器闭包生成数组
     *
     * @param $fn 生成器闭包
     */
    public static function repeatFnGenerator(Closure $fn): array
    {
        $arr = [];
        foreach ($fn() as $item) {
            $arr[] = $item;
        }
        return $arr;
    }

    /**
     * 应用一个闭包数组
     *
     * @param array<Closure>|\Traversable<Closure> $array 所有闭包的参数必须为无参
     *
     * @return bool
     */
    public static function applys(array|\Traversable $array)
    {
        foreach ($array as $item) {
            ($item)();
        }
        return true;
    }


    /**
     * 转换一维数组为多级数组
     * @param array $list 一维数组
     * @param string $field 主键的字段名
     * @param string $parent_field 关联父级的字段名
     * @param string|int $start_index 起始位置
     * @param string $children_name 写入子级数据的字段名
     * @return array
     */
    public static function getChildrenList(
        array $list,
        string $field = 'id',
        string $parent_field = 'parent_id',
        string|int $start_index = 0,
        string $children_name = 'children',
    ): array
    {
        //按父级生成索引数组
        $index_data = [];
        foreach ($list as $item) {
            $index_data[$item[$parent_field]][] = $item;
        }
        unset($item);

        return self::setChildren($index_data, $start_index, $field, $children_name);
    }

    /**
     * 写入子级数据
     * @param array $index_data 索引数组，主键是对应的父级字段的值
     * @param string|int $start_index 起始位置
     * @param string $field 主键的字段名
     * @param string $children_name 写入子级数据的字段名
     * @return array
     */
    private static function setChildren(
        array $index_data,
        string|int $start_index,
        string $field,
        string $children_name
    ): array
    {
        if (isset($index_data[$start_index])){
            $list = $index_data[$start_index];
            foreach ($list as &$item) {
                $children = self::setChildren($index_data, $item[$field], $field, $children_name);
                if (count($children) > 0) {
                    $item[$children_name] = $children;
                }
            }
            return $list;

        }else{
            return [];
        }
    }
}
